﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Ordinapoche.Core;

namespace Ordinapoche.WinForms
{
    public partial class ProcessorControl : UserControl
    {
        private Processor _Processor;

        public ProcessorControl ()
        {
            InitializeComponent ();

            menu_ClockSpeed.SelectedIndex = 0;
            menu_Multiplier.SelectedIndex = 0;
        }

        private void Detach (Processor aProcessor)
        {

        }

        private void Attach (Processor aProcessor)
        {
            aProcessor.ProgramCounterChanged += Processor_ProgramCounterChanged;
            aProcessor.AccumulatorChanged += Processor_AccumulatorChanged;
            aProcessor.InstructionRegisterChanged += Processor_InstructionChanged;
            aProcessor.AluResultChanged += Processor_AluResultChanged;
            aProcessor.TempValueChanged += Processor_TempValueChanged;
            aProcessor.ReadyChanged += Processor_ReadyChanged;
        }

        public Processor Processor
        {
            get
            {
                return _Processor;
            }
            set
            {
                if (value != _Processor)
                {
                    if (_Processor != null)
                    {
                        Detach (_Processor);
                    }
                    _Processor = value;
                    if (_Processor != null)
                    {
                        Attach (_Processor);
                    }
                    Processor_Changed ();
                }
            }
        }

        void Processor_Changed ()
        {
            RegisterChangeEventArgs e = new RegisterChangeEventArgs (0, 0);
            Processor_AccumulatorChanged (this, e);
            Processor_ProgramCounterChanged (this, e);
            Processor_AluResultChanged (this, e);
            Processor_TempValueChanged (this, e);
            Processor_ReadyChanged (this, e);
        }

        void Processor_AccumulatorChanged (object sender, RegisterChangeEventArgs e)
        {
            if (_Processor != null)
            {
                text_Accumulator.Text = _Processor.Accumulator.ToString ();
            }
            else
            {
                text_Accumulator.Text = String.Empty;
            }
        }

        void Processor_ProgramCounterChanged (object sender, RegisterChangeEventArgs e)
        {
            if (_Processor != null)
            {
                text_ProgramCounter.Text = _Processor.ProgramCounter.ToString ();
            }
            else
            {
                text_ProgramCounter.Text = String.Empty;
            }
        }

        void Processor_InstructionChanged (object sender, RegisterChangeEventArgs e)
        {
            if (_Processor != null)
            {
                text_Instruction.Text = _Processor.InstructionRegister.ToString ();
            }
            else
            {
                text_Instruction.Text = String.Empty;
            }
        }


        void Processor_TempValueChanged (object sender, RegisterChangeEventArgs e)
        {
            if (_Processor != null)
            {
                text_TempValue.Text = _Processor.TempValue.ToString ();
            }
            else
            {
                text_TempValue.Text = String.Empty;
            }
        }

        void Processor_AluResultChanged (object sender, RegisterChangeEventArgs e)
        {
            if (_Processor != null)
            {
                text_AluResult.Text = _Processor.AluResult.ToString ();
            }
            else
            {
                text_AluResult.Text = String.Empty;
            }
        }

        void Processor_ReadyChanged (object sender, EventArgs e)
        {
            EnableDisable ();
            button_Step.Enabled = _Processor != null && _Processor.Ready;
        }

        private void EnableDisable ()
        {
            bool Ready = _Processor != null && _Processor.Ready;
            bool Running = timer_Run.Enabled;
            bool CanRun = Ready && !Running;

            button_Step.Enabled = CanRun;
            menu_Step.Enabled = CanRun;
            menu_Run.Enabled = CanRun;
            menu_Stop.Enabled = Running;
        }

        private void SingleStep ()
        {
            if (_Processor != null)
            {
                _Processor.ExecuteOneStep ();
            }
        }

        private void Run ()
        {
            timer_Run.Enabled = true;
        }

        private void Stop ()
        {
            timer_Run.Enabled = false;
        }

        private void button_Step_Click (object sender, EventArgs e)
        {
            SingleStep ();
        }

        private void timer_Run_Tick (object sender, EventArgs e)
        {
            SingleStep ();
        }

        private void menu_Step_Click (object sender, EventArgs e)
        {
            SingleStep ();
        }

        private void menu_Run_Click (object sender, EventArgs e)
        {
            Run ();
        }

        private void menu_Stop_Click (object sender, EventArgs e)
        {
            Stop ();
        }

        private void menu_ClockSpeed_SelectedIndexChanged (object sender, EventArgs e)
        {
            switch (menu_ClockSpeed.SelectedIndex)
            {
                case 0:
                    timer_Run.Interval = 1000;
                    break;
                case 1:
                    timer_Run.Interval = 100;
                    break;
                case 2:
                    timer_Run.Interval = 10;
                    break;
            }
        }

        private void menu_Multiplier_SelectedIndexChanged (object sender, EventArgs e)
        {
            if (_Processor != null)
            {
                switch (menu_Multiplier.SelectedIndex)
                {
                    case 0:
                        _Processor.ClockMultiplier = 1;
                        break;
                    case 1:
                        _Processor.ClockMultiplier = 2;
                        break;
                    case 2:
                        _Processor.ClockMultiplier = 5;
                        break;
                    case 3:
                        _Processor.ClockMultiplier = 10;
                        break;
                }
            }
        }

    }
}
